#pragma once

#include <vector>
#include <algorithm>

namespace gtl
{

template<class T, int Size = 0>
class array
{
public:
	typedef T value_type;
	typedef T* pointer_type;

public:
	enum { m_size = Size };

public:
	array()
	{
		memset(m_array, 0, m_size * sizeof(T)); 
	}

	explicit array(const T arr[m_size])
	{
		memcpy(m_array, arr, m_size * sizeof(T));
	}

	array(const array& arr)
	{
		memcpy(m_array, arr.m_array, m_size * sizeof(T));
	}

	~array()
	{
	}

public:
	T& operator[](int i)
	{
		return m_array[i];
	}

	operator T*() const
	{
		return (T*)m_array;
	}

	int size()
	{
		return m_size;
	}

	array& operator=(const T arr[m_size])
	{
		memcpy(m_array, arr, m_size * sizeof(T));
		return *this;
	}

	array& operator=(const array& arr)
	{
		if(&arr == this)
			return *this;

		memcpy(m_array, arr.m_array, m_size * sizeof(T));
		return *this;
	}

	bool operator==(const array& arr) const
	{
		return memcmp(m_array, arr.m_array, m_size * sizeof(T)) == 0;
	}

	bool operator==(T arr[m_size]) const
	{
		return memcmp(m_array, arr, m_size * sizeof(T)) == 0;
	}

	bool operator==(const T arr[m_size]) const
	{
		return memcmp(m_array, arr, m_size * sizeof(T)) == 0;
	}

	void operator()(const T arr[m_size])
	{
		memcpy(m_array, arr, m_size * sizeof(T));
	}

	void operator()(const T* arr, int sz)
	{
		sz = min(m_size, sz);
		if(arr == NULL || sz <= 0)
			return;

		memcpy(m_array, arr, sz * sizeof(T));
	}

private:
	T m_array[m_size];
};

template<class T>
class array<T, 0>
{
public:
	typedef T value_type;
	typedef T* pointer_type;

public:
	array(int size = 0)
	{
		m_size = 0;
		m_array = NULL;
		resize(size);
	}

	array(const T* arr, int size)
	{
		m_size = 0;
		m_array = NULL;
		assign(arr, size);
	}

	array(const array& arr)
	{
		m_size = 0;
		m_array = NULL;
		assign(arr.m_array, arr.m_size);
	}

	~array()
	{
		reset();
	}
	
public:
	void operator=(T* arr)
	{
		reset();
		m_array = arr;
	}

	array& operator=(const array& arr)
	{
		if(this == &arr)
			return *this;

		return assign(arr.m_array, arr.m_size);
	}

	array& assign(const T* arr, int size)
	{
		reset();
		if(arr == NULL || size <= 0)
			return *this;

		resize(size);
		memcpy(m_array, arr, size * sizeof(T));
		return *this;
	}

	array& copy(int offset, T* data, int len)
	{
		if(offset >= m_size)
			return *this;

		if(m_size - offset < len)
			len = m_size - offset;

		memcpy(m_array + offset, data, len);
		return *this;
	}

	void reset()
	{
		m_size = 0;
		if(m_array != NULL)
			free(m_array);

		m_array = NULL;
	}

	void resize(int size)
	{
		if(size <= 0)
			return reset();

		T* arr = (T*)realloc(m_array, size * sizeof(T));
		if(arr == NULL)
			return;

		m_array = arr;
		if(m_size < size)
			memset(m_array + m_size, 0, (size - m_size) * sizeof(T));

		m_size = size;
	}

public:
	T& operator[](int i)
	{
		return m_array[i];
	}

	const T& operator[](int i) const
	{
		return m_array[i];
	}

	operator T*() const
	{
		return m_array;
	}

	T** operator&()
	{
		return &m_array;
	}

	T** operator&() const
	{
		return &m_array;
	}

public:
	bool operator==(const array& arr) const
	{
		if(m_size != arr.m_size || m_size == 0 || arr.m_size == 0)
			return false;

		return memcmp(m_array, arr.m_array, m_size * sizeof(T)) == 0;
	}

public:
	int size() const
	{
		return m_size;
	}

	bool empty() const
	{
		return m_size <= 0;
	}

	void operator()(const T* arr, int sz)
	{
		sz = min(m_size, sz);
		if(arr == NULL || sz <= 0)
			return;

		memcpy(m_array, arr, sz * sizeof(T));
	}

private:
	int m_size;
	T* m_array;
};

template<class Array>
void trans(std::vector<typename Array::pointer_type>& vecTPtr, const std::vector<Array>& vecTArr)
{
	for(size_t i = 0; i < vecTArr.size(); i++)
	{
		vecTPtr.push_back(vecTArr[i]);
	}
}

} // end of namespace gtl